import {
  type DataInfo,
  formatToken,
  getToken as getAuthToken,
  removeToken,
  setToken as setAuthToken
} from "@/utils/auth";
import axios, { type AxiosInstance } from "axios";
import { CancelController } from "./cancel";
import { getConfig } from "./config";
import { HookSystem } from "./hooks";
import {
  createRequestInterceptor,
  createResponseInterceptor
} from "./interceptors";
import { Logger } from "./logger";
import type {
  CustomRequestConfig,
  HookCallback,
  HookType,
  HttpResponse
} from "./types";

/**
 * HTTP 客户端类
 * 封装 axios，提供统一的 API
 */
export class HttpClient {
  private instance: AxiosInstance;
  private cancelController: CancelController;
  private logger: Logger;
  private hooks: HookSystem;

  /**
   * 构造函数
   * @param config 请求配置
   */
  constructor(config: CustomRequestConfig = {}) {
    // 创建 axios 实例
    this.instance = axios.create(getConfig(config));

    // 初始化工具类
    this.cancelController = new CancelController();
    this.logger = new Logger();
    this.hooks = new HookSystem();

    // 初始化拦截器
    this.setupInterceptors();
  }

  /**
   * 设置拦截器
   */
  private setupInterceptors(): void {
    // 请求拦截器
    const requestInterceptor = createRequestInterceptor(
      this.cancelController,
      this.logger,
      this.hooks,
      this.getToken.bind(this)
    );

    this.instance.interceptors.request.use(
      requestInterceptor.onFulfilled,
      requestInterceptor.onRejected
    );

    // 响应拦截器
    const responseInterceptor = createResponseInterceptor(
      this.cancelController,
      this.logger,
      this.hooks,
      this.clearToken.bind(this)
    );

    this.instance.interceptors.response.use(
      responseInterceptor.onFulfilled,
      responseInterceptor.onRejected
    );
  }

  /**
   * 获取 token
   * @returns token 字符串或 null
   */
  private getToken(): string | null {
    const tokenData = getAuthToken();
    if (!tokenData || !tokenData.token) return null;
    return formatToken(tokenData.token);
  }

  /**
   * 保存 token 及相关信息
   * @param data token数据对象
   */
  public setToken(data: DataInfo<number>): void {
    setAuthToken(data);
  }

  /**
   * 清除 token
   */
  public clearToken(): void {
    removeToken();
  }

  /**
   * 添加钩子
   * @param type 钩子类型
   * @param callback 钩子回调函数
   */
  public addHook(type: HookType, callback: HookCallback): void {
    this.hooks.addHook(type, callback);
  }

  /**
   * 移除钩子
   * @param type 钩子类型
   * @param callback 钩子回调函数
   */
  public removeHook(type: HookType, callback: HookCallback): void {
    this.hooks.removeHook(type, callback);
  }

  /**
   * 取消所有请求
   */
  public cancelAllRequests(): void {
    this.cancelController.cancelAllRequests();
  }

  /**
   * 设置全局配置
   * @param config 请求配置
   */
  public setConfig(config: CustomRequestConfig): void {
    Object.assign(this.instance.defaults, config);
  }

  /**
   * 设置日志级别
   * @param level 日志级别
   */
  public setLogLevel(level: "debug" | "info" | "warn" | "error"): void {
    this.logger.setLevel(level);
  }

  /**
   * 启用日志
   */
  public enableLog(): void {
    this.logger.enable();
  }

  /**
   * 禁用日志
   */
  public disableLog(): void {
    this.logger.disable();
  }

  /**
   * 通用请求方法
   * @param config 请求配置
   * @returns Promise 包含响应数据
   */
  public async request<T = any>(
    config: CustomRequestConfig
  ): Promise<HttpResponse<T>> {
    try {
      const response = await this.instance.request<HttpResponse<T>>(config);
      return response as any;
    } catch (error) {
      return Promise.reject(error);
    }
  }

  /**
   * GET 请求
   * @param url 请求地址
   * @param param 请求参数
   * @param config 请求配置
   * @returns Promise 包含响应数据
   */
  public get<T = any>(
    url: string,
    param?: any,
    config?: CustomRequestConfig
  ): Promise<HttpResponse<T>> {
    return this.instance.get(url, {
      params: param,
      ...config
    });
  }

  /**
   * POST 请求
   * @param url 请求地址
   * @param data 请求数据
   * @param config 请求配置
   * @returns Promise 包含响应数据
   */
  public post<T = any>(
    url: string,
    data?: any,
    config?: CustomRequestConfig
  ): Promise<HttpResponse<T>> {
    return this.instance.post(url, data, config);
  }

  /**
   * PUT 请求
   * @param url 请求地址
   * @param data 请求数据
   * @param config 请求配置
   * @returns Promise 包含响应数据
   */
  public put<T = any>(
    url: string,
    data?: any,
    config?: CustomRequestConfig
  ): Promise<HttpResponse<T>> {
    return this.instance.put(url, data, config);
  }

  /**
   * DELETE 请求
   * @param url 请求地址
   * @param config 请求配置
   * @returns Promise 包含响应数据
   */
  public delete<T = any>(
    url: string,
    config?: CustomRequestConfig
  ): Promise<HttpResponse<T>> {
    return this.instance.delete(url, config);
  }

  /**
   * PATCH 请求
   * @param url 请求地址
   * @param data 请求数据
   * @param config 请求配置
   * @returns Promise 包含响应数据
   */
  public patch<T = any>(
    url: string,
    data?: any,
    config?: CustomRequestConfig
  ): Promise<HttpResponse<T>> {
    return this.instance.patch(url, data, config);
  }

  /**
   * HEAD 请求
   * @param url 请求地址
   * @param config 请求配置
   * @returns Promise 包含响应数据
   */
  public head<T = any>(
    url: string,
    config?: CustomRequestConfig
  ): Promise<HttpResponse<T>> {
    return this.instance.head(url, config);
  }

  /**
   * OPTIONS 请求
   * @param url 请求地址
   * @param config 请求配置
   * @returns Promise 包含响应数据
   */
  public options<T = any>(
    url: string,
    config?: CustomRequestConfig
  ): Promise<HttpResponse<T>> {
    return this.instance.options(url, config);
  }
}
